<?php

namespace App\Library\Logic;

use App\Library\Requests\Base\BasePageRequest;
use App\Library\Requests\Category\ShopCategoryActivityTypeRequest;
use App\Library\Requests\Product\ProductAddRequest;
use App\Library\Requests\Product\ProductCustomerServicePagingRequest;
use App\Library\Requests\Product\ProductEditRequest;
use App\Library\Requests\Product\ProductPageRequest;
use App\Library\Requests\Product\ProductUserPageRequest;
use App\Library\Requests\Product\TjRequest;
use App\Library\Traits\Logic\ShopProductLogicTrait;
use App\Models\ShopProductModel;
use App\Models\ShopProductSpecsModel;
use Exception;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\DB;

class ShopProductLogic extends ShopProductModel
{
    use ShopProductLogicTrait;

    /**
     * add
     * @param ProductAddRequest $request
     * @return Model
     * @throws Exception
     */
    public function add(ProductAddRequest $request): Model
    {
        $model = self::insertForModel(array_merge($this->saveCom($request), [
            'userId' => MAINID,
            'addUserId' => USERID,
            'createdTime' => now(),
        ]));
        if (!empty($model->ps_id_json))
            ShopProductSpecsModel::query()
                ->whereIn('ps_id', json_decode($model->ps_id_json, true))->update(['product_id' => $model->product_id]);
        return $model;
    }

    /**
     * 获取活动商品分类信息
     * @param ShopCategoryActivityTypeRequest $request
     * @return array
     *
     */
    public static function findByActivityType(ShopCategoryActivityTypeRequest $request): array
    {
        return self::query()->where([
            'product_activity' => 1,
            'product_activity_type' => $request->productActivityType
        ])
            ->distinct()->pluck('product_category_id_2')->toArray();
    }

    /**
     * edit
     * @param ProductEditRequest $request
     * @param Model $self
     * @return Model
     */
    public function edit(ProductEditRequest $request, Model $self): Model
    {
        $data = $this->saveCom($request);
        if (!isset($data['descImgIds'])) $data['descImgIds'] = null;
        if (!isset($data['videoId'])) $data['videoId'] = null;
        return self::updateForModel($data, $self);
    }

    /**
     * 产品统计
     * @param TjRequest $request
     * @param Model|Builder $user
     * @return Model|Builder
     *
     */
    public function tj(TjRequest $request, Model|Builder $user): Model|Builder
    {
        $builder = self::query()->where('plug2', $request->flag ?? 0);
        if (!is_null($request->productName)) $builder->where('product_name', 'like', '%' . $request->productName . '%');
        if (!is_null($request->startAt) && !is_null($request->endAt)) {
            $builder->whereBetween('created_at', [
                strtotime(now()->parse($request->startAt)->startOfDay()->format('Y-m-d H:i:s')),
                strtotime(now()->parse($request->endAt)->endOfDay()->format('Y-m-d H:i:s'))
            ]);
        }

        if (USERID === MAINID || POWER === 1) $builder->where('user_id', MAINID);
        else $builder->where('add_user_id', USERID);

        $result = $builder->select([
            DB::raw('count(if(product_status = 1, true, null)) as draft_count'),
            DB::raw('count(if(product_status = 2, true, null)) as published_count'),
            DB::raw('count(if(product_stock_empty = 2 || product_stock_empty = 3, true, null)) as sold_out_count'),
        ])->first();


        $result['buy_will_count'] = self::buyWillTj($request);
        return $result;
    }

    private function buyWillTj(TjRequest $request): int
    {
        $builder = BuyWillLogic::query()->where(['status' => 1]);
        if (USERID === MAINID || POWER === 1) $builder->where('user_id', MAINID);
        else $builder->where('add_user_id', USERID);

        if (!is_null($request->productName)) {
            $builder->where(function ($query) use ($request) {
                $query->where('title', 'like', '%' . $request->productName . '%')
                    ->orWhere('description', 'like', '%' . $request->productName . '%');
            });
        }

        if (!is_null($request->startAt) && !is_null($request->endAt)) {
            $builder->whereBetween('created_at', [
                now()->parse($request->startAt)->startOfDay()->format('Y-m-d H:i:s'),
                now()->parse($request->endAt)->endOfDay()->format('Y-m-d H:i:s')
            ]);
        }
        return $builder->count();
    }

    /**
     * 日统计
     * @param $request
     * @return Collection|array
     */
    public function dayTj($request): Collection|array
    {
        $builder = self::query();
        if (!is_null($request->keyword)) $builder->where('product_name', 'LIKE', '%' . $request->keyword . '%');

        if ($request->type === 0 || is_null($request->type)) {
            $builder->where('product_status', 2)->select(
                DB::raw('count(*) as day_count'),
                'publish_at as day'
            )->whereIn('publish_at', $request->times)->groupBy('publish_at')->orderByDesc('publish_at');
        } else if ($request->type === 1) {
            $builder->where('product_status', 1)->select(
                DB::raw('count(*) as day_count'),
                DB::raw('LEFT(created_time, 10) as day')
            )->whereIn('created_time', $request->times)->groupBy('created_time')->orderByDesc('created_time');
        } else if ($request->type === 2) $builder->whereIn('product_stock_empty', [2, 3]);

        if (USERID === MAINID || POWER === 1) $builder->where('user_id', MAINID);
        else $builder->where('add_user_id', USERID);

        return $builder->get();
    }

    public function paging(ProductPageRequest $request): array
    {
        $builder = self::query()
            ->where('plug2', 0)
            ->with(['categoryOne', 'categoryTwo', 'categoryThree']);
        if ($request->status === 0 || is_null($request->status)) $builder->where('product_status', 2)->orderBy('publish_at', $request->orderBy);
        else if ($request->status === 1) $builder->where('product_status', 1)->orderBy('created_time', $request->orderBy);
        else if ($request->status === 2) $builder->whereIn('product_stock_empty', [2, 3])->orderByDesc('created_at');

        if (MAINID !== config('superId') && is_null($request->header('newAuth'))) {
            if (USERID === MAINID || POWER === 1) $builder->where('user_id', MAINID);
            else $builder->where('add_user_id', USERID);
        }

        if (!is_null($request->startAt)) {
            $builder->whereBetween('created_at', [
                strtotime(now()->parse($request->startAt)->startOfDay()->format('Y-m-d H:i:s')),
                strtotime(now()->parse($request->endAt)->endOfDay()->format('Y-m-d H:i:s'))
            ]);
        }
        if (!is_null($request->keyword)) $builder->where('product_name', 'LIKE', '%' . $request->keyword . '%');

        return paginate($builder->paginate($request->limit, [
            'serial_number',
            'product_id',
            'product_special_start_time',
            'product_special_end_time',
            'product_avatar',
            'product_name',
            'product_status',
            'product_stock_empty',
            'product_category_id_1',
            'product_category_id_2',
            'product_category_id_3',
            'created_time',
            'publish_at',
            'add_at'
        ]));
    }

    /**
     * 用户产品列表
     * @param ProductUserPageRequest $request
     * @return array
     */
    public function userPaging(ProductUserPageRequest $request): array
    {
        $where = ['product_status' => 2, 'plug' => 0, 'plug2' => 0, 'is_agent' => $request->isAgent === true ? 1 : 0];
        if ($request->productCategoryIdOne === 1 && $request->productCategoryIdTwo === null) {
            if (!request()->has('productCategoryIdTwo') && request()->has('productName')) {
                $where['product_category_id_1'] = 1;
            }
        } else {
            if (!is_null($request->productCategoryIdOne) && $request->productCategoryIdOne > 0) {
                $where['product_category_id_1'] = $request->productCategoryIdOne;
            }
            if (!is_null($request->productCategoryIdTwo) && $request->productCategoryIdTwo > 0) {
                $where['product_category_id_2'] = $request->productCategoryIdTwo;
            }
            if (!is_null($request->productCategoryIdThree) && $request->productCategoryIdThree > 0) {
                $where['product_category_id_3'] = $request->productCategoryIdThree;
            }
        }
        if (!is_null($request->isBlackGold) && $request->isBlackGold === true) $where[] = ['sub_price', '>', 0];
        if (!is_null($request->isCommission) && $request->isCommission === true) $where['is_commission'] = 1;
        if ($request->productActivityType > 0) {
            $where['product_activity'] = 1;
            $where['product_activity_type'] = $request->productActivityType;
        }
        if (!is_null($request->productName)) {
            $like = htmlspecialchars(strip_tags(trim($request->productName)));
            if (!empty($like)) $where[] = ['product_name', 'like', '%' . $like . '%'];
        }
        if (!is_null($request->productBrand)) {
            $like = htmlspecialchars(strip_tags(trim($request->productBrand)));
            if (!empty($like)) $where[] = ['product_brand', 'like', '%' . $like . '%'];
        }
        $builder = self::query()->where($where);
        $categoryIdThreeArr = match ($request->allCategoryIdThree) {
            1 => [7, 11, 15],
            2 => [8, 12, 16],
            3 => [9, 13, 17],
            4 => [10, 14, 18],
            default => null,
        };
        if (!is_null($categoryIdThreeArr)) $builder->whereIn('product_category_id_3', $categoryIdThreeArr);
        if ($request->productCategoryIdOne === 0 && $request->productCategoryIdTwo === 23) {
            $builder->whereNotIn('product_category_id_3', [24]);
        }

        return paginate($builder->orderByDesc('status_recommend')->orderBy('sort')->paginate($request->limit));
    }


    /**
     * 用户产品列表
     * @param ProductUserPageRequest $request
     * @return array
     */
    public static function goodList(ProductUserPageRequest $request): array
    {
        $where = ['product_status' => 2, 'plug' => 0, 'plug2' => 0, 'is_agent' => $request->isAgent === true ? 1 : 0];
        if ($request->productCategoryIdOne === 1 && $request->productCategoryIdTwo === null) {
            if (!request()->has('productCategoryIdTwo') && request()->has('productName')) {
                $where['product_category_id_1'] = 1;
            }
        } else {
            if (!is_null($request->productCategoryIdOne) && $request->productCategoryIdOne > 0) {
                $where['product_category_id_1'] = $request->productCategoryIdOne;
            }
            if (!is_null($request->productCategoryIdTwo) && $request->productCategoryIdTwo > 0) {
                $where['product_category_id_2'] = $request->productCategoryIdTwo;
            }
            if (!is_null($request->productCategoryIdThree) && $request->productCategoryIdThree > 0) {
                $where['product_category_id_3'] = $request->productCategoryIdThree;
            }
        }
        if (!is_null($request->isBlackGold) && $request->isBlackGold === true) $where[] = ['sub_price', '>', 0];
        if (!is_null($request->isCommission) && $request->isCommission === true) $where['is_commission'] = 1;
        if ($request->productActivityType > 0) {
            $where['product_activity'] = 1;
            $where['product_activity_type'] = $request->productActivityType;
        }
        if (!is_null($request->productName)) {
            $like = htmlspecialchars(strip_tags(trim($request->productName)));
            if (!empty($like)) $where[] = ['product_name', 'like', '%' . $like . '%'];
        }
        if (!is_null($request->productBrand)) {
            $like = htmlspecialchars(strip_tags(trim($request->productBrand)));
            if (!empty($like)) $where[] = ['product_brand', 'like', '%' . $like . '%'];
        }

        $builder = self::query()->where($where);
        $categoryIdThreeArr = match ($request->allCategoryIdThree) {
            1 => [7, 11, 15],
            2 => [8, 12, 16],
            3 => [9, 13, 17],
            4 => [10, 14, 18],
            default => null,
        };
        if (!is_null($categoryIdThreeArr)) $builder->whereIn('product_category_id_3', $categoryIdThreeArr);
        if ($request->productCategoryIdOne === 0 && $request->productCategoryIdTwo === 23) {
            $builder->whereNotIn('product_category_id_3', [24]);
        }

        return paginate($builder->orderByDesc('status_recommend')->orderBy('sort')->paginate($request->limit));
    }

    public function recommendList(BasePageRequest $request): array
    {
        return paginate(ShopProductLogic::query()
            ->where([
                'status_recommend' => 1,
                'product_status' => 2,
                'plug' => 0
            ])
            ->where('product_stock_empty', 1)
            ->orderByDesc('product_total_sell')->paginate($request->limit, [
                'product_id',
                'product_special_start_time',
                'product_special_end_time',
                'product_avatar',
                'product_name',
                'product_status',
                'product_stock_empty',
                'product_category_id_1',
                'product_category_id_2',
                'product_category_id_3',
                'created_time',
                'publish_at',
                'add_at'
            ]));
    }

    /**
     * handle
     * @param Model $self
     * @param int|null $userId
     * @return Model
     * @throws Exception
     */
    public static function copy(Model $self, ?int $userId = null): Model
    {
        $productId = $self->product_id;
        self::unsetProduct($self);
        $new = self::insertForModel(array_merge($self->toArray(), [
            'userId' => $userId ?? MAINID,
            'addUserId' => $userId ?? USERID,
            'editUserId' => $userId ?? USERID,
            'createdTime' => now()->toDateString(),
        ]));
        $specList = ShopProductSpecsLogic::getByWhere('productId', $productId);
        $psIdJson = $specJson = [];
        foreach ($specList as $v) {
            ShopProductSpecsLogic::unsetSpec($v);
            $spec = ShopProductSpecsLogic::insertForModel(array_merge($v->toArray(), [
                'productId' => $new->product_id,
                'userId' => $userId ?? MAINID,
                'psTotalStock' => $v->ps_usable_stock,
            ]));
            $psIdJson[] = $spec->ps_id;
            $specJson[] = $spec->serial_number;
            cache(['shopProductSpec:' . $spec->serial_number => $spec->ps_id]);
        }
        $new->ps_id_json = empty($psIdJson) ? null : json_encode($psIdJson);
        $new->spec_json = $specJson ?? null;
        $new->save();
        mq('shopProductChange', $new);
        OperateLogLogic::add();
        return $new;
    }

    /**
     * adminTj
     * @return array
     */
    public function adminTj(): array
    {
        return $this->newQuery()->groupBy('product_status')
            ->pluck(DB::raw('count(*) as count'), 'product_status')->toArray();
    }

    /**
     * sales
     * @param int $orderId
     * @param int $sub
     * @return void
     */
    public static function saveSale(int $orderId, int $sub = 0): void
    {
        //if (prod()) return;
        $list = ShopOrderGoodsLogic::getByWhere('orderId', $orderId, ['productId', 'specId', 'quantity']);
        foreach ($list as $v) {
            $shopProduct = ShopProductLogic::detail($v->product_id, ['productId', 'sales']);
            if (!is_null($shopProduct)) {
                if ($sub === 1) $shopProduct->sales -= $v->quantity;
                else $shopProduct->sales += $v->quantity;
                $shopProduct->save();
            }
            $shopProductSpecs = ShopProductSpecsLogic::detail($v->spec_id, ['psId', 'sales']);
            if (!is_null($shopProductSpecs)) {
                if ($sub === 1) $shopProductSpecs->sales -= $v->quantity;
                else $shopProductSpecs->sales += $v->quantity;
                $shopProductSpecs->save();
            }
        }
    }

    public static function editStock(Model $self): void
    {
        $aggregate = ShopProductSpecsLogic::sumByWhere('product_id', $self->product_id, 'psUsableStock');
        ShopProductlogic::updateByWhere(['productStockEmpty' => $aggregate > 0 ? 1 : 2], 'productId', $self->product_id);
        $sales = ShopOrderGoodsLogic::query()->leftJoin('shop_order_ext', 'shop_order_ext.order_id', 'shop_order_goods.order_id')
            ->where('shop_order_goods.product_id', $self->product_id)
            ->whereIn('status', [4, 5])->sum('quantity');
        $refund = ShopOrderReturnLogic::query()
            ->leftJoin('shop_order_goods', 'shop_order_goods.order_id', 'shop_order_return.order_id')
            ->where('shop_order_goods.product_id', $self->product_id)
            ->whereIn('shop_order_return.or_sell_status', [2, 4, 5, 6])
            ->sum('shop_order_goods.quantity');
        $productTotalSell = max(($sales - $refund), 0);
        $self->product_total_sell = $productTotalSell;
        $self->save();
    }

    public function customerServicePaging(ProductCustomerServicePagingRequest $request): array
    {
        $paginate = self::query()->where([
            'user_id' => $request->sellerId,
            'product_status' => 2
        ]);
        if (!is_null($request->keyword)) $paginate->where('product_name', 'like', '%' . $request->keyword . '%');
        $paginate = $paginate->orderByDesc('created_at')->paginate($request->limit);
        return paginate($paginate);
    }

    /**
     *
     * @param array $shopUserId
     * @param array $productsId
     * @return Collection|array
     */
    public function buyWillList(array $shopUserId, array $productsId): Collection|array
    {
        $builder = self::query()
            ->leftJoin('shop_product_specs', 'shop_product.product_id', 'shop_product_specs.product_id')
            ->where([
                'shop_product.buy_will' => 1,
                'shop_product.product_status' => 2,
                'shop_product.product_stock_empty' => 1
            ])
            ->whereIn('shop_product.user_id', $shopUserId);
        if (!empty($productsId)) $builder->whereNotIn('shop_product.product_id', $productsId);
        return $builder->orderByRaw('RAND()')
            ->limit(__('com.buyWillPageCount'))
            ->distinct()
            ->get(['shop_product.product_id', 'shop_product.product_name', 'shop_product.serial_number', 'product_avatar']);
    }

    public static function reduce(int $start, int $plugHour): int
    {
        if (now()->timestamp < $start) return $start - time() + 3600;
        $hour = now()->diffInHours(now()->timestamp($start)) % $plugHour;
        $hour = $hour === 0 ? $plugHour : abs($hour - $plugHour);
        return $hour * 3600 - now()->diffInSeconds(now()->startOfHour());
    }
}
